﻿#pragma once

#ifndef QCEFWIDGET_H
#define QCEFWIDGET_H

#include <QtCore>
#include <QtGui>
#include <QtWidgets>
#include <QMetaType>

#include "ExtendWidget.h"

#include "QCefDebug.h"
#include "QCefContext.h"
#include "QCefClient.h"
#include "QCefDelegate.h"

//
typedef QMultiMap<QString, QString> QStrMultiMap;
typedef QMap<QString, QString>      QStrMap;

//
class QCefWidget : public ExtendWidget
{
    Q_OBJECT
public:
    enum BrowserState
    {
        bsNone = -1,
        bsCreating = 0,
        bsCreated = 1,
    };    

public:
    QCefWidget(QWidget * parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());
    QCefWidget(const QString & strUrl, QWidget * parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());
    virtual ~QCefWidget();

public:    
    virtual int finiCefCtrl();
    virtual int browserCreated(CefRefPtr<CefBrowser> browser);

protected:
    virtual int createContainer();
    virtual int createClient();

    //createBrowser需要在窗体show后调用。
    virtual int createBrowser(const QString & strUrl = "", const QSize & size = QSize(), DWORD style = 0, DWORD ex_style = 0);
    virtual int resizeBrowser(const QSize & size);


public:
    int loadRequest(const QString& strUrl, const QString& strMethod = "GET", const QString& strPostData = "", const QStrMultiMap& header = QStrMultiMap());

    int load(const QString & strUrl);
    int load(const QUrl & url);

    int loadUrl(const QString & strUrl);
    int loadUrl(const QUrl & url);

    QString getUrl();
    int setUrl(const QString & strUrl);

    WId getPageWId();
    bool canGoBack();
    void goBack();
    bool canGoForward();
    void goForward();
    bool isLoading();
    void reload();
    void reloadIgnoreCache();
    void stopLoad();
    void setBrowserFocus(bool focus = true);

    bool waitPageCreate(qint64 msec = 10*60*1000);
    bool waitPageCreateSleep(qint64 msec = 10*60*1000);

    //
    bool toHtml(const std::function<void(const QString &)> & resultCallback, int64 frameId = 0);

    bool runJavaScript(const QString & strCode, int64 frameId = 0);
    bool runJavaScriptAsyncResult(int id, const QString & strCode, int64 frameId = 0);

    bool runJavaScriptFull(const QString & strCode);
    bool runJavaScriptAsyncResultFull(int id, const QString & strCode);

public:
    CefRefPtr<QCefClient> getClient() { return m_client; }
    CefRefPtr<QCefDelegate> getDelegate() { return m_delegate; }
    CefRefPtr<CefBrowser> & getBrowser() { return m_browser; }

    BrowserState getBrowserState() { return m_browserState; }
    QString getFirstUrl() { return m_strFirstUrl; }
    void setFirstUrl(const QString & strUrl) { m_strFirstUrl = strUrl; }

    //请求过滤
    int getRequestFilter() { return m_iReqFilter; }
    void setRequestFilter(int val) { m_iReqFilter = val; }
    QStringList& getRequestFilterUrlKeys() { return m_reqFilterKeys; }
    void addRequestFilterUrlKey(const QString & strUrlKey) { m_reqFilterKeys.append(strUrlKey); m_iReqFilter = 1; }
    bool findRequestFilter(QString strMethod, QString strUrl, int iResourceType, QString & strKey);

    int getRequestCompleteFilter() { return m_iReqCompleteFilter; }
    void setRequestCompleteFilter(int val) { m_iReqCompleteFilter = val; }

    //响应数据过滤
    int getResponseFilter() { return m_iResFilter; }
    void setResponseFilter(int val) { m_iResFilter = val; }
    QStringList & getResponseFilterUrlKeys() { return m_resFilterKeys; }
    void addResponseFilterUrlKey(const QString & strUrlKey) { m_resFilterKeys.append(strUrlKey); m_iResFilter = 1; }
    bool findResponseFilter(QString strMethod, QString strUrl, int iResourceType, QString & strKey);

    //下载文件
    int getSignalDownProgress() { return m_iSignalDownProgress; }
    void setSignalDownProgress(int val) { m_iSignalDownProgress = val; }
    bool isDownloadFile(QString strOrgUrl, QString strUrl);
    QString getDownFilePath() { return m_strSaveFilePath; }
    bool startDownload(const QString & strUrl, const QString & strSaveFilePath);

protected:
    CefRefPtr<QCefClient>   m_client;
    CefRefPtr<QCefDelegate> m_delegate;
    CefRefPtr<CefBrowser>   m_browser;
    BrowserState            m_browserState;
    QString                 m_strFirstUrl;
    int                     m_iLoadFirstUrl;

    //NCW用的变量
    QVBoxLayout *   m_layout;
    QWindow *       m_window;
    QWidget *       m_container;

    //请求过滤，按照url中的关键字来过滤请求    
    int             m_iReqFilter;
    QStringList     m_reqFilterKeys;
    int             m_iReqCompleteFilter;

    //响应数据过滤，按照url的关键字来过滤响应数据
    int             m_iResFilter;
    QStringList     m_resFilterKeys;

    //调用startDownload下载文件时
    int             m_iSignalDownProgress;  //下载过程产生通知
    QString         m_strDownloadUrl;       //startDownload的URL
    QString         m_strSaveFilePath;      //startDownload保存的文件

protected:
    virtual void firstPolishEvent(QEvent * event) override;
    virtual void resizeEvent(QResizeEvent * event) override;
    virtual void closeEvent(QCloseEvent *event) override;
    virtual QSize sizeHint() const override;

public slots:
    void onPageAfterCreated();

signals:
    //////////////////////////////////////////////////////////////////////////
    //CefClient
    void pageReportJavaScriptResult(int id, QVariant ret);
    void pageFocusedEditableNodeChanged(bool focusOnEditableField);

    //////////////////////////////////////////////////////////////////////////
    //CefLifeSpanHandler
    void pageBeforePopup(QString url, QString title, int disposition, bool user_gesture);
    void pageAfterCreated();
    void pageDoClose();
    void pageBeforeClose();

    //////////////////////////////////////////////////////////////////////////
    //CefLoadHandler
    void pageLoadingStateChange(bool isLoading, bool canGoBack, bool canGoForward);
    void pageLoadStart(int transition_type);
    void pageLoadEnd(int httpStatusCode);
    void pageLoadError(int errorCode, QString errorText, QString failedUrl);

    //////////////////////////////////////////////////////////////////////////
    //CefDisplayHandler
    void pageAddressChange(QString url);
    void pageTitleChange(QString title);
    void pageFaviconURLChange(QStringList icon_urls);
    void pageFullscreenModeChange(bool fullscreen);
    void pageTooltip(QString text);
    void pageStatusMessage(QString value);
    void pageConsoleMessage(int level, QString message, QString source, int line);
    void pageAutoResize(QSize new_size);
    void pageLoadingProgressChange(double progress);
    void pageCursorChange(int type);
    //根据faviconURLChange扩展而来
    void pageFaviconChange(QString strImageUrl, int http_status_code, QIcon icon);

    //////////////////////////////////////////////////////////////////////////
    //CefFocusHandler
    void pageTakeFocus(bool next);
    void pageSetFocus(int source);
    void pageGotFocus();

    //////////////////////////////////////////////////////////////////////////
    //CefRenderHandler
    void pagePopupShow(bool show);
    void pagePopupSize(QRect rt);
    void pagePaint(int type, QRegion region, QImage image, int width, int height);
    void pageAcceleratedPaint(int type, QRegion region, void * shared_handle);
    void pageScrollOffsetChanged(double x, double y);
    void pageImeCompositionRangeChanged(int from, int to, QRect rt);
    void pageTextSelectionChanged(int from, int to, QString strSelectedText);
    void pageVirtualKeyboardRequested(int input_mode);

    //////////////////////////////////////////////////////////////////////////
    //CefRequestHandler

    //////////////////////////////////////////////////////////////////////////
    //CefResourceRequestHandler
    void pageBeforeResourceLoad(QString strKey, QString strMethod, QString strUrl, int iResourceType);
    void pageResponseFilterComplete(QString strKey, QString strMethod, QString strUrl, int iResourceType, QByteArray data);
    void pageResourceLoadComplete(QString strKey, QString strMethod, QString strUrl, int iResourceType, QStrMultiMap req, QStrMultiMap res);

    //////////////////////////////////////////////////////////////////////////
    //CefDownloadHandler
    void pageDownloadUpdated(QString strUrl, QString strFilePath, int iDownStatus, qint64 iTotalBytes, qint64 iReceivedBytes, int percent);
};

//
Q_DECLARE_METATYPE(QStrMultiMap)
Q_DECLARE_METATYPE(QStrMap)

#endif // QCEFWIDGET_H
